package com.logistics.utils.aspect.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.logistics.log.entity.model.LogSave;
import com.logistics.log.service.LogService;
import com.logistics.utils.aspect.annotation.LoggerListener;
import com.logistics.utils.constants.Dictionary;
import com.logistics.utils.constants.LoggerMethod;
import com.logistics.utils.exception.JwtTimeoutException;
import com.logistics.utils.exception.MessageException;
import com.logistics.utils.exception.RenewalException;
import com.logistics.utils.tool.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;


@Aspect
@Order(-1)
@Component
@ConditionalOnProperty(name = {"configure.logger"}, matchIfMissing = true)
public class LoggerListenerAspect {

    @Autowired
    private LogService logService;


    @Pointcut("@annotation(com.logistics.utils.aspect.annotation.LoggerListener)")
    public void listerLoggerListener(){}

    /**
     * 方法请求之前
     * @param point
     */
    @Around("listerLoggerListener()")
    public Object beforeLoggerListener(ProceedingJoinPoint point) throws Throwable {LogSave save = getRequestInfo(point);
        Object res = point.proceed();
        JSONObject json = JSONObject.parseObject(new ObjectMapper().writeValueAsString(res));
        String httpStatus = json.getString("statusCodeValue");
        String body = json.getString("body");
        String type = Dictionary.LOGTYPEOPERATION.getCode();
        // 返回结果
        save.setContext(body);
        // 类型
        save.setType(type);
        // http返回状态码
        save.setStatus(httpStatus);
        logService.save(save);
        return res;
    }


    /**
     * 异常处理
     * @param exception
     */
    @AfterThrowing(pointcut = "listerLoggerListener()", throwing = "exception")
    public void afterResultBeforeLoggerListener(JoinPoint joinPoint, Exception exception) throws JsonProcessingException {
        LogSave save = getRequestInfo(joinPoint);
        if(exception instanceof MessageException ||
                exception instanceof JwtTimeoutException ||
                exception instanceof RenewalException){
            save.setType("1");
            save.setStatus("200");
            save.setContext(exception.getMessage());
        }else{
            save.setType("2");
            save.setStatus("500");
            // 错误消息
            StringWriter sw = new StringWriter();
            exception.printStackTrace(new PrintWriter(sw, true));
            save.setContext(sw.getBuffer().toString());
        }
        logService.save(save);
    }

    /**
     * 获取请求信息
     * @param point
     * @return
     * @throws JsonProcessingException
     */
    protected LogSave getRequestInfo(JoinPoint point) throws JsonProcessingException {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request =  requestAttributes.getRequest();
        String requestAddress = request.getRequestURL().toString();
        String requestMethod = request.getMethod();
        Object param = point.getArgs().length > 0 ? point.getArgs()[0] : null;
        MethodSignature signature = (MethodSignature) point.getSignature();
        LoggerListener annotation = signature.getMethod().getAnnotation(LoggerListener.class);
        String businessName = annotation.businessName();
        LoggerMethod methodName = annotation.methodName();
        LogSave save = new LogSave();
        save.setBusinessName(businessName);
        // 执行方法
        save.setMethod(signature.getName());
        // 方法名
        save.setMethodName(methodName.getName());
        // 请求地址
        save.setRequestAddress(requestAddress);
        // 请求方法
        save.setRequestMethod(requestMethod);
        // 参数
        save.setParameter(new ObjectMapper().writeValueAsString(param));
        return save;
    }

}
